﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace LianXian
{
    /// <summary>
    /// LianXianWindow.xaml 的交互逻辑
    /// </summary>
    public partial class LianXianWindow : Window
    {

        private readonly Line _line = new Line();
        private List<KeyValuePair<Data, Data>> _guanXi = new List<KeyValuePair<Data, Data>>();

        public List<KeyValuePair<Data, Data>> GuanXi
        {
            get { return _guanXi; }
            set { _guanXi = value; }
        }

        public LianXianWindow(IEnumerable<Data> leftDatas, IEnumerable<Data> rightDatas)
        {
            InitializeComponent();


            TreeViewLeft.ItemsSource = leftDatas;
            TreeViewRight.ItemsSource = rightDatas;

            _line.Stroke = new SolidColorBrush(Colors.Black);
            _line.StrokeThickness = 2;
            _line.Opacity = 1;

            _line.IsHitTestVisible = false;
        }

        #region 事件

        private void UIElement_OnMouseDown(object sender, MouseButtonEventArgs e)
        {
            FrameworkElement fe = sender as FrameworkElement;
            if (fe == null) return;

            Point point = e.GetPosition(CanvasDrawing);
            _line.X1 = point.X;
            _line.Y1 = point.Y;

            _line.X2 = point.X;
            _line.Y2 = point.Y;

            _line.Tag = new GuanXi { StartElement = fe };

            CanvasDrawing.Children.Add(_line);
        }


        private void Grid_OnMouseMove(object sender, MouseEventArgs e)
        {
            if (!CanvasDrawing.Children.Contains(_line)) return;
            Point point = e.GetPosition(CanvasDrawing);
            _line.X2 = point.X;
            _line.Y2 = point.Y;
        }

        private void Grid_OnMouseUp(object sender, MouseButtonEventArgs e)
        {
            CanvasDrawing.Children.Remove(_line);
        }

        private void UIElement_OnMouseUp(object sender, MouseButtonEventArgs e)
        {
            if (CanvasDrawing.Children.Contains(_line))
            {
                CanvasDrawing.Children.Remove(_line);

                FrameworkElement fe = sender as FrameworkElement;
                if (fe == null) return;

                GuanXi gx = _line.Tag as GuanXi;
                if (gx == null) return;

                gx.EndElement = fe;

                if (gx.StartElement == gx.EndElement) return;

                Line l = CreateNewLine();

                CalculateStartEndPoint(l);

                CanvasDrawing.Children.Add(l);
            }
        }


        /// <summary>
        /// 在线上按下鼠标
        /// 添加当前线的效果,充当选中效果
        /// 去掉其它线的效果
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Line_OnMouseDown(object sender, MouseButtonEventArgs e)
        {
            Line l = sender as Line;

            if (l == null) return;
            DropShadowEffect sde = new DropShadowEffect();
            sde.Color = Colors.Blue;
            sde.ShadowDepth = 0;
            sde.Opacity = 1;
            sde.BlurRadius = 4;

            foreach (Line result in CanvasDrawing.Children.OfType<Line>())
            {
                result.Effect = result == l ? sde : null;
            }
        }


        private void Window_OnKeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key != Key.Delete) return;

            //查找选中的线
            Line result = CanvasDrawing.Children.OfType<Line>().SingleOrDefault(l => l.Effect != null);

            CanvasDrawing.Children.Remove(result);
        }

        private void Window_OnClosed(object sender, EventArgs e)
        {
            _guanXi.Clear();

            foreach (Line line in CanvasDrawing.Children.OfType<Line>())
            {
                GuanXi gx = line.Tag as GuanXi;
                if (gx == null) continue;
                Data kData = gx.StartElement.DataContext as Data;
                Data vData = gx.EndElement.DataContext as Data;
                KeyValuePair<Data, Data> kv = new KeyValuePair<Data, Data>(kData, vData);

                if (!_guanXi.Exists(k => k.Key.Name == kv.Key.Name && k.Value.Name == kv.Value.Name))
                {
                    _guanXi.Add(kv);
                }
            }

        }


        #endregion


        private Line CreateNewLine()
        {
            Line l = new Line
            {
                X1 = _line.X1,
                Y1 = _line.Y1,
                X2 = _line.X2,
                Y2 = _line.Y2,
                Tag = _line.Tag,
                Stroke = _line.Stroke,
                StrokeThickness = _line.StrokeThickness,
                Cursor = Cursors.Hand
            };

            l.MouseDown += Line_OnMouseDown;
            return l;
        }


        /// <summary>
        /// 重新计算线的起点和终点
        /// </summary>
        /// <param name="line"></param>
        private void CalculateStartEndPoint(Line line)
        {
            GuanXi gx = line.Tag as GuanXi;
            if (gx == null) return;


            FrameworkElement startFrameworkElement = gx.StartElement;
            FrameworkElement endFrameworkElement = gx.EndElement;



            Point a1 = startFrameworkElement.TranslatePoint(new Point(0, startFrameworkElement.ActualHeight / 2),
                CanvasDrawing);
            Point a2 = startFrameworkElement.TranslatePoint(new Point(startFrameworkElement.ActualWidth, startFrameworkElement.ActualHeight / 2),
               CanvasDrawing);

            Point b1 = endFrameworkElement.TranslatePoint(new Point(0, endFrameworkElement.ActualHeight / 2),
                CanvasDrawing);
            Point b2 = endFrameworkElement.TranslatePoint(new Point(endFrameworkElement.ActualWidth, endFrameworkElement.ActualHeight / 2),
                CanvasDrawing);

            Point a = new Point();
            Point b = new Point();

            double d = double.MaxValue;

            // a1 b1 , a1 b2
            double temp = CalculateDistance(a1, b1);
            if (d > temp)
            {
                a = a1;
                b = b1;
                d = temp;
            }

            temp = CalculateDistance(a1, b2);
            if (d > temp)
            {
                a = a1;
                b = b2;
                d = temp;
            }

            //a2 b1, a2 b2
            temp = CalculateDistance(a2, b1);
            if (d > temp)
            {
                a = a2;
                b = b1;
                d = temp;
            }

            temp = CalculateDistance(a2, b2);
            if (d > temp)
            {
                a = a2;
                b = b2;
                d = temp;
            }
            line.X1 = a.X;
            line.Y1 = a.Y;
            line.X2 = b.X;
            line.Y2 = b.Y;

        }

        /// <summary>
        /// 计算两点之间的距离
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        double CalculateDistance(Point a, Point b)
        {
            return Math.Abs(Math.Sqrt(Math.Pow(a.X - b.X, 2) + Math.Pow(a.Y - b.Y, 2)));
        }



        public void SetGuanXi(List<KeyValuePair<Data, Data>> guanXi)
        {
            _guanXi = guanXi;
            InvalidateVisual();
        }

        protected override void OnRender(DrawingContext drawingContext)
        {
            base.OnRender(drawingContext);
            if (_guanXi.Count != 0)
            {
                foreach (KeyValuePair<Data, Data> keyValuePair in _guanXi)
                {
                    Line line = CreateNewLine();

                    GuanXi gx = new GuanXi
                    {
                        StartElement =
                            BindingHelper.FindElementFromBindingData<TextBlock>(TreeViewLeft, keyValuePair.Key),
                        EndElement =
                            BindingHelper.FindElementFromBindingData<TextBlock>(TreeViewRight, keyValuePair.Value)
                    };
                    line.Tag = gx;
                    CanvasDrawing.Children.Add(line);
                }
                _guanXi.Clear();
            }
            foreach (Line line in CanvasDrawing.Children.OfType<Line>())
            {
                CalculateStartEndPoint(line);
            }

        }
    }
}
